import UIKit
class Person {
    var name : String
    var department: Department? = nil
    
    init(name: String) {
        self.name = name
    }
    
    deinit {
        print("person deinit")
    }
}

class Department {
    let depName: String
    weak var person: Person?
    init(depName: String) {
        self.depName = depName
    }
    deinit {
        print("department deinit")
    }
}

var p:Person?
var d:Department?

p = Person(name: "John Appleseed")
d = Department(depName: "It部门")
p?.department = d
d?.person = p

p = nil
d = nil

class Customer {
    let name: String
    var card: CreditCard?
    
    init(name: String) {
        self.name = name
    }
    deinit {
        print("\(name) is being deinitialized.")
    }
 }

class CreditCard {
    let number : Int
    unowned var customer:Customer
    init(number: Int, customer: Customer) {
        self.number = number
        self.customer = customer
    }
    deinit {
        print("Card \(number) is being deinit.")
    }
}


var join: Customer?
join = Customer(name: "John Applest")
join?.card = CreditCard(number: 1234_121211, customer: join!)
join = nil


class Country {
    let name: String
    var capitalCity:City!
    init(name: String) {
        self.name = name
    }
    
    deinit {
        print("country deinit")
    }
}

class City {
    let name:String
    unowned let country: Country
    init(name: String, country: Country) {
        self.name = name
        self.country = country
    }
    
    deinit {
        print("city deinit.")
    }
}

var country = Country(name: "Canada")
country.capitalCity = City(name: "otawwac", country: country)
print("\(country.name)'s capital city is called \(country.capitalCity.name)")

//闭包引起的循环引用。循环引用发生在当一个闭包赋值给类实例的某个属性，并且这个闭包体又引用了实例。

class HTMLElement {
    let name: String
    let text: String?
    lazy var asHTML:() -> String = {
        [unowned self] in
        if let text = self.text {
            return "<\(self.name)>\(text)</\(self.name)>"
        } else {
            return "<\(self.name)/>"
        }
    }
    
    init(name: String, text: String? = nil) {
        self.name = name
        self.text = text
    }
    
    deinit {
        print("\(name) is being deinitized.")
    }
}

var paragraph: HTMLElement? = HTMLElement(name: "p", text: "hello,world")
print(paragraph!.asHTML())
paragraph = nil

// 解决闭包引起的循环引用.在定义闭包时同时定义捕获列表作为闭包的一部分。

//定义捕获列表。捕获列表中的每个元素都是有weak或unowner关键字和实例的引用如（self 或 someInstance）成对组成，没对都在方括号中，通过逗号分开。如下例子。
//lazy var someClousure: (Int, String) -> String {
//    [unowned self] (index:Int, stringTopProcess:String) -> String in
//    
//    //clouser body
//}

//如果闭包没有指定参数列表或者返回类型，则可以通过上下文推断。那么可以把捕获列表放在闭包开始的地方。
//lazy var someClousure: (Int, String) -> String {
//    [unowned self]  in
//
//    //clouser body
//}
